package cn.wizzer.app.user.modules.service.impl;

import cn.wizzer.app.sys.modules.models.SysCurrency;
import cn.wizzer.app.sys.modules.models.constant.CurrencyConstant;
import cn.wizzer.app.sys.modules.services.SysCurrencyService;
import cn.wizzer.app.user.modules.models.UserExchange;
import cn.wizzer.app.user.modules.models.enums.BizTypeEnum;
import cn.wizzer.app.user.modules.models.enums.UserColEnum;
import cn.wizzer.app.user.modules.models.vo.ExchangeVO;
import cn.wizzer.app.user.modules.services.account.UserAccountRecordService;
import cn.wizzer.app.user.modules.services.account.UserExchangeService;
import cn.wizzer.framework.base.model.enums.BizExceptionEnum;
import cn.wizzer.framework.base.service.BaseServiceImpl;
import cn.wizzer.framework.base.service.CommonDBService;
import cn.wizzer.framework.page.Pagination;
import cn.wizzer.framework.util.Id;
import cn.wizzer.framework.util.Result;
import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.dubbo.config.annotation.Service;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Dao;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Strings;

import java.math.BigDecimal;
import java.util.Map;

@IocBean(args = {"refer:dao"})
@Service(interfaceClass = UserExchangeService.class)
public class UserExchangeServiceImpl extends BaseServiceImpl<UserExchange> implements UserExchangeService {
    public UserExchangeServiceImpl(Dao dao) {
        super(dao);
    }

    @Inject
    private CommonDBService dbService;

    @Inject
    @Reference
    private SysCurrencyService currencyService;

    @Inject
    private UserAccountRecordService recordService;

    @Aop(TransAop.REPEATABLE_READ)
    @Override
    public UserExchange exchange(BigDecimal amount, String fromCurrencyId, String toCurrencyId, String appid, String channel) {
        SysCurrency fromCurrency = currencyService.getById(fromCurrencyId);
        SysCurrency toCurrency = currencyService.getById(toCurrencyId);
        if("API".equals(channel)){
            // 前端用户不能操作体验金互换
            if (fromCurrency.getName().equals(CurrencyConstant.EXP)
                    || toCurrency.getName().equals(CurrencyConstant.EXP)) {
                Result.breakWith(BizExceptionEnum.USD_EXP_CANNOT_EXCHANGE);
            }
        }
        BigDecimal resultAmount = amount.divide(toCurrency.getRate(), 2, BigDecimal.ROUND_HALF_DOWN).multiply(fromCurrency.getRate());
        UserExchange exchange = insert(fromCurrencyId, amount, toCurrencyId, resultAmount, appid);
        recordService.add(fromCurrencyId, appid, amount, BizTypeEnum.EXCHANGE_OUT, exchange.getId(), exchange.getNo());
        recordService.add(toCurrencyId, appid, resultAmount, BizTypeEnum.EXCHANGE_IN, exchange.getId(), exchange.getNo());
        return exchange;
    }

    private UserExchange insert(String fromCurrencyId, BigDecimal amount, String toCurrencyId, BigDecimal resultAmount, String appid) {
        UserExchange exchange = new UserExchange();
        exchange.setFromAmount(amount);
        exchange.setFromCurrencyId(fromCurrencyId);
        exchange.setToAmount(resultAmount);
        exchange.setToCurrencyId(toCurrencyId);
        exchange.setNo(Id.createOrderNo());
        exchange.setUserId(appid);
        this.insert(exchange);
        return exchange;
    }

    @Override
    public ExchangeVO fetchVO(String id, String appid) {
        return dbService.fetchSql(ExchangeVO.class, Sqls.create("select e.*,fc.rate fromCurrencyRate," +
                "tc.rate toCurrencyRate,fc.name fromCurrencyName,tc.name toCurrencyName from user_exchange e")
                .appendSourceSql("left join sys_currency fc on fc.id=e.fromCurrencyId")
                .appendSourceSql("left join sys_currency tc on tc.id=e.toCurrencyId")
                .appendSourceSql("where e.id = @id and userId = @userId")
                .appendSourceSql("limit 1")
                .setParam("id", id)
                .setParam("userId", appid)
                .toString());
    }

    @Override
    public Pagination queryVO(String userCnd, String no, String userId, String fromCurrencyId, String toCurrencyId, int pageNumber, int pageSize, Long startTime, Long endTime) {
        Sql sql = Sqls.create("select e.*,u.userName,u.nickName,u.email,fc.rate fromCurrencyRate,fc.name fromCurrencyName," +
                "tc.rate toCurrencyRate,tc.name toCurrencyName from user_exchange e")
                .appendSourceSql("left join sys_currency fc on fc.id=e.fromCurrencyId")
                .appendSourceSql("left join sys_currency tc on tc.id=e.toCurrencyId")
                .appendSourceSql("left join user u on u.id=e.userId")
                .appendSourceSql("where 1=1 ");
        // 勾选的用户条件
        if (Strings.isNotBlank(userCnd)) {
            String[] split = userCnd.split(",");
            for (String col : split) {
                String colName = UserColEnum.getValByName(col);
                if (Strings.isNotBlank(colName)) {
                    // 默认不显示游客、内部账号
                    sql.appendSourceSql("and u.").appendSourceSql(colName).appendSourceSql(" = 0");
                }
            }
        }
        if (Strings.isNotBlank(no)) {
            sql.appendSourceSql("and e.no = @no");
            sql.setParam("no", no);
        }
        if (Strings.isNotBlank(userId)) {
            sql.appendSourceSql("and e.userId = @userId");
            sql.setParam("userId", userId);
        }
        if (startTime != null) {
            sql.appendSourceSql("and e.ctAt >= @startTime");
            sql.setParam("startTime", startTime);
        }
        if (endTime != null) {
            sql.appendSourceSql("and e.ctAt < @endTime");
            sql.setParam("endTime", endTime);
        }
        if (Strings.isNotBlank(fromCurrencyId)) {
            sql.appendSourceSql("and e.fromCurrencyId = @fromCurrencyId");
            sql.setParam("fromCurrencyId", fromCurrencyId);
        }
        if (Strings.isNotBlank(toCurrencyId)) {
            sql.appendSourceSql("and e.toCurrencyId = @toCurrencyId");
            sql.setParam("toCurrencyId", toCurrencyId);
        }
        sql.appendSourceSql("order by e.ctAt desc");
        String sqlStr = sql.toString();
        return dbService.listPage(ExchangeVO.class, pageNumber, pageSize, sqlStr);
    }

    @Override
    public Map<String, BigDecimal> searchSum(String userCnd, String no, String userId, String fromCurrencyId, String toCurrencyId, int pageNumber, int pageSize, Long startTime, Long endTime) {
        Sql sql = Sqls.create("select IFNULL(sum(e.fromAmount * fc.rate), 0) AS fromAmount,")
                .appendSourceSql("IFNULL(sum(e.toAmount * tc.rate), 0) AS toAmount")
                .appendSourceSql("from user_exchange e")
                .appendSourceSql("left join sys_currency fc on fc.id=e.fromCurrencyId")
                .appendSourceSql("left join sys_currency tc on tc.id=e.toCurrencyId")
                .appendSourceSql("left join user u on u.id=e.userId")
                .appendSourceSql("where 1=1 ");
        // 勾选的用户条件
        if (Strings.isNotBlank(userCnd)) {
            String[] split = userCnd.split(",");
            for (String col : split) {
                String colName = UserColEnum.getValByName(col);
                if (Strings.isNotBlank(colName)) {
                    // 默认不显示游客、内部账号
                    sql.appendSourceSql("and u.").appendSourceSql(colName).appendSourceSql(" = 0");
                }
            }
        }
        if (Strings.isNotBlank(no)) {
            sql.appendSourceSql("and e.no = @no");
            sql.setParam("no", no);
        }
        if (Strings.isNotBlank(userId)) {
            sql.appendSourceSql("and e.userId = @userId");
            sql.setParam("userId", userId);
        }
        if (startTime != null) {
            sql.appendSourceSql("and e.ctAt >= @startTime");
            sql.setParam("startTime", startTime);
        }
        if (endTime != null) {
            sql.appendSourceSql("and e.ctAt < @endTime");
            sql.setParam("endTime", endTime);
        }
        if (Strings.isNotBlank(fromCurrencyId)) {
            sql.appendSourceSql("and e.fromCurrencyId = @fromCurrencyId");
            sql.setParam("fromCurrencyId", fromCurrencyId);
        }
        if (Strings.isNotBlank(toCurrencyId)) {
            sql.appendSourceSql("and e.toCurrencyId = @toCurrencyId");
            sql.setParam("toCurrencyId", toCurrencyId);
        }
        sql.setCallback(Sqls.callback.map());
        this.dao().execute(sql);
        UserExchange sum = sql.getObject(UserExchange.class);
        return Result.createMap("fromAmount", sum.getFromAmount(),
                "toAmount", sum.getToAmount());
    }
}
